/**
 * @file main.c
 * @author WHXY
 * @brief
 * @version 0.1
 * @date 2024-08-07
 *
 * @copyright Copyright (c) 2022
 *
 */
/*******************************************************************************
*
* 代码许可和免责信息
* 武汉芯源半导体有限公司授予您使用所有编程代码示例的非专属的版权许可，您可以由此
* 生成根据您的特定需要而定制的相似功能。根据不能被排除的任何法定保证，武汉芯源半
* 导体有限公司及其程序开发商和供应商对程序或技术支持（如果有）不提供任何明示或暗
* 含的保证或条件，包括但不限于暗含的有关适销性、适用于某种特定用途和非侵权的保证
* 或条件。
* 无论何种情形，武汉芯源半导体有限公司及其程序开发商或供应商均不对下列各项负责，
* 即使被告知其发生的可能性时，也是如此：数据的丢失或损坏；直接的、特别的、附带的
* 或间接的损害，或任何后果性经济损害；或利润、业务、收入、商誉或预期可节省金额的
* 损失。
* 某些司法辖区不允许对直接的、附带的或后果性的损害有任何的排除或限制，因此某些或
* 全部上述排除或限制可能并不适用于您。
*
*******************************************************************************/
/******************************************************************************
 * Include files
 ******************************************************************************/
#include "main.h"
#include "interrupts_cw32l010.h"
/******************************************************************************
 * Local pre-processor symbols/macros ('#define')
 ******************************************************************************/
//UARTx
#define  DEBUG_UARTx                   CW_UART1
#define  DEBUG_UART_CLK                SYSCTRL_APB1_PERIPH_UART1
#define  DEBUG_UART_APBClkENx          SYSCTRL_APBPeriphClk_Enable1
#define  DEBUG_UART_BaudRate           115200
#define  DEBUG_UART_UclkFreq           8000000

//UARTx GPIO
#define  DEBUG_UART_GPIO_CLK           (SYSCTRL_AHB_PERIPH_GPIOA)
#define  DEBUG_UART_TX_GPIO_PORT       CW_GPIOA
#define  DEBUG_UART_TX_GPIO_PIN        GPIO_PIN_6
#define  DEBUG_UART_RX_GPIO_PORT       CW_GPIOA
#define  DEBUG_UART_RX_GPIO_PIN        GPIO_PIN_5

//GPIO AF
#define  DEBUG_UART_AFTX               PA06_AFx_UART1TXD()
#define  DEBUG_UART_AFRX               PA05_AFx_UART1RXD()

//中断
#define  DEBUG_UART_IRQ                UART1_IRQn



// 开发阶段
#define  DEBUG_MODE			1   

/******************************************************************************
 * Global variable definitions (declared in header file with 'extern')
 ******************************************************************************/
ring_buffer_t g_ring;
#define RX_LEN	128
uint8_t rx_buffer[RX_LEN];

/******************************************************************************
 * Local type definitions ('typedef')
 ******************************************************************************/

/******************************************************************************
 * Local function prototypes ('static')
 ******************************************************************************/
void RCC_Configuration(void);
void GPIO_Configuration(void);
void UART_Configuration(void);
void PWM_OutputConfig(void);
void ATIM_Configuration(void);
void NVIC_Configuration(void);
void UART_SendString(UART_TypeDef *UARTx, char *String);

void Protocol_parse();

/******************************************************************************
 * Local variable definitions ('static')                                      *
 ******************************************************************************/

/******************************************************************************
 * Local pre-processor symbols/macros ('#define')
 ******************************************************************************/

/*****************************************************************************
 * Function implementation - global ('extern') and local ('static')
 ******************************************************************************/


/**
 ******************************************************************************
 ** \brief  Main function of project
 **
 ** \return uint32_t return value, if needed
 **
 ******************************************************************************/
int32_t main(void)
{
    //配置RCC
    RCC_Configuration();

    //配置GPIO
    GPIO_Configuration();

    //配置UART
    UART_Configuration();
	
		//配置PWM
		PWM_OutputConfig();
		
		//配置ATIM
		ATIM_Configuration();
		
		//配置NVIC
		NVIC_Configuration();
		
		// 初始化环形队列
		ring_buffer_init(&g_ring, rx_buffer, RX_LEN);
		
			//使能UARTx RC中断
		UART_ITConfig(DEBUG_UARTx, UART_IT_RC, ENABLE);
		UART_ClearITPendingBit(DEBUG_UARTx, UART_IT_RC);
		
		UART_SendData_8bit(DEBUG_UARTx,0x66);
		printf("\r\nCW32L010 START\r\n");
    while(1)
    {
		//轮询解析
		Protocol_parse();
    }
}

/**
 * @brief 配置RCC
 *
 */
void RCC_Configuration(void)
{
	/* 0. HSI使能并校准 */
    //SYSCTRL_HSI_Enable(SYSCTRL_HSIOSC_DIV12);
	SYSCTRL_HSI_Enable(SYSCTRL_HSIOSC_DIV6);

    /* 1. 设置HCLK和PCLK的分频系数　*/
    SYSCTRL_HCLKPRS_Config(SYSCTRL_HCLK_DIV1);
    SYSCTRL_PCLKPRS_Config(SYSCTRL_PCLK_DIV1);
  
    SYSCTRL_SystemCoreClockUpdate(4000000);
	
	//外设时钟使能
    SYSCTRL_AHBPeriphClk_Enable(DEBUG_UART_GPIO_CLK, ENABLE);
    DEBUG_UART_APBClkENx(DEBUG_UART_CLK, ENABLE);
	
}                            

/**
 * @brief 配置GPIO
 *
 */
void GPIO_Configuration(void)
{
	///////////////////////////////////串口初始化///////////////////////////////////
    GPIO_InitTypeDef GPIO_InitStructure = {0};

    GPIO_InitStructure.Pins = DEBUG_UART_TX_GPIO_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Init(DEBUG_UART_TX_GPIO_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.Pins = DEBUG_UART_RX_GPIO_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
    GPIO_Init(DEBUG_UART_RX_GPIO_PORT, &GPIO_InitStructure);

    //UART TX RX 复用
    DEBUG_UART_AFTX;
    DEBUG_UART_AFRX;
	
	
	 /* PB4 作为GTIM1的CH3 PWM 输出 */
    __SYSCTRL_GPIOB_CLK_ENABLE();
	__SYSCTRL_GPIOA_CLK_ENABLE();
	__SYSCTRL_ATIM_CLK_ENABLE();
		
		
		///////////////////////////////剩余引脚用在GPIO上//////////////////////////////////
		// PA1 PA2 PA4 PB2
		GPIO_InitStructure.Pins = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
		
		GPIO_InitStructure.Pins = GPIO_PIN_2;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Init(CW_GPIOB, &GPIO_InitStructure);
		
		
		
		
		

    ////////////////////////////通用定时器//////////////////////////////
	  // B3 B4 B5 B6 B0 B1  A3 A0
		PB03_DIGTAL_ENABLE();
    PB03_DIR_OUTPUT();
    PB03_PUSHPULL_ENABLE();
    PB03_AFx_GTIM1CH4();
    
    PB04_DIGTAL_ENABLE();
    PB04_DIR_OUTPUT();
    PB04_PUSHPULL_ENABLE();
    PB04_AFx_GTIM1CH3();
	
		PB05_DIGTAL_ENABLE();
    PB05_DIR_OUTPUT();
    PB05_PUSHPULL_ENABLE();
    PB05_AFx_GTIM1CH2();
	
		PB06_DIGTAL_ENABLE();
    PB06_DIR_OUTPUT();
    PB06_PUSHPULL_ENABLE();
    PB06_AFx_GTIM1CH1();
		
		
	////////////////////////////高级定时器//////////////////////////////
		GPIO_InitTypeDef GPIO_InitStruct = {0};
    PB00_DIGTAL_ENABLE();
    
    GPIO_InitStruct.IT = GPIO_IT_NONE;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pins = GPIO_PIN_0;
    GPIO_Init(CW_GPIOB, &GPIO_InitStruct);
    
    
    GPIO_InitStruct.IT = GPIO_IT_NONE;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pins = GPIO_PIN_1;
    GPIO_Init(CW_GPIOB, &GPIO_InitStruct); 
		
		GPIO_InitStruct.IT = GPIO_IT_NONE;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pins = GPIO_PIN_3;
    GPIO_Init(CW_GPIOA, &GPIO_InitStruct); 
		
		GPIO_InitStruct.IT = GPIO_IT_NONE;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pins = GPIO_PIN_0;
    GPIO_Init(CW_GPIOA, &GPIO_InitStruct); 
    
    
    PB00_AFx_ATIMCH1();
    PB01_AFx_ATIMCH2();
		PA03_AFx_ATIMCH3();
		PA00_AFx_ATIMCH4();
		
	///////////////////////////////////低功PWM输出//////////////////////////////////////
	// PA05为LPTIM的输出OUT    
    //GPIO_InitStruct.IT = GPIO_IT_NONE;
    //GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    //GPIO_InitStruct.Pins = GPIO_PIN_4;
    //GPIO_Init(CW_GPIOA, &GPIO_InitStruct);
    //PA04_AFx_LPTIMCH2();
}

/**
 * @brief 配置UART
 *
 */
void UART_Configuration(void)
{
    UART_InitTypeDef UART_InitStructure = {0};

    UART_InitStructure.UART_BaudRate = DEBUG_UART_BaudRate;
    UART_InitStructure.UART_Over = UART_Over_16;
    UART_InitStructure.UART_Source = UART_Source_PCLK;
    UART_InitStructure.UART_UclkFreq = DEBUG_UART_UclkFreq;
    UART_InitStructure.UART_StartBit = UART_StartBit_FE;
    UART_InitStructure.UART_StopBits = UART_StopBits_1;
    UART_InitStructure.UART_Parity = UART_Parity_No ;
    UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;
    UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;
    UART_Init(DEBUG_UARTx, &UART_InitStructure);
}

/**
 * @brief 配置NVIC
 *
 */
void NVIC_Configuration(void)
{
    //优先级，无优先级分组
    NVIC_SetPriority(DEBUG_UART_IRQ, 0);
    //UARTx中断使能
    NVIC_EnableIRQ(DEBUG_UART_IRQ);
}

/*************************** 舵机控制 *************************************/

void PWM_OutputConfig(void)
{
    GTIM_InitTypeDef GTIM_InitStruct = {0};
    GTIM_OCModeCfgTypeDef GTIM_OCModeCfgStruct = {DISABLE,DISABLE,0};

    __SYSCTRL_GTIM1_CLK_ENABLE();

    GTIM_InitStruct.AlignMode = GTIM_ALIGN_MODE_EDGE;
    GTIM_InitStruct.ARRBuffState = GTIM_ARR_BUFF_EN;
    GTIM_InitStruct.Direction = GTIM_DIRECTION_UP;
    GTIM_InitStruct.EventOption = GTIM_EVENT_NORMAL;
    GTIM_InitStruct.Prescaler = 8 - 1;  
    GTIM_InitStruct.PulseMode = GTIM_PULSE_MODE_DIS;
    GTIM_InitStruct.ReloadValue = 20000 - 1;
    GTIM_InitStruct.UpdateOption = GTIM_UPDATE_DIS;
    GTIM_TimeBaseInit(CW_GTIM1, &GTIM_InitStruct);
    
    
    GTIM_OCModeCfgStruct.FastMode = DISABLE;
    GTIM_OCModeCfgStruct.OCMode = GTIM_OC_MODE_PWM1;
    GTIM_OCModeCfgStruct.OCPolarity = GTIM_OC_POLAR_NONINVERT;
    GTIM_OCModeCfgStruct.PreloadState = DISABLE;
		
		GTIM_OC4ModeCfg(CW_GTIM1, &GTIM_OCModeCfgStruct);
		GTIM_OC3ModeCfg(CW_GTIM1, &GTIM_OCModeCfgStruct);
		GTIM_OC2ModeCfg(CW_GTIM1, &GTIM_OCModeCfgStruct);
    GTIM_OC1ModeCfg(CW_GTIM1, &GTIM_OCModeCfgStruct);
		
    
    GTIM_SetCompare4(CW_GTIM1, 0);
    GTIM_OC4Cmd(CW_GTIM1, ENABLE);
		
		GTIM_SetCompare3(CW_GTIM1, 0);
    GTIM_OC3Cmd(CW_GTIM1, ENABLE);
		
		GTIM_SetCompare2(CW_GTIM1, 0);
    GTIM_OC2Cmd(CW_GTIM1, ENABLE);
		
		GTIM_SetCompare1(CW_GTIM1, 0);
    GTIM_OC1Cmd(CW_GTIM1, ENABLE);
		
    GTIM_Cmd(CW_GTIM1, ENABLE);
}


#define  compare1     500
#define  compare2     500 
#define  ARRS         20000 - 1   
void ATIM_Configuration(void)
{
    ATIM_InitTypeDef ATIM_InitStruct = {DISABLE,0};
    ATIM_OCInitTypeDef ATIM_OCInitStruct = {0};
    
    // 对ATIM进行计数的基本设置   
    ATIM_InitStruct.BufferState = DISABLE;     //不启用ARR的缓存功能    
    ATIM_InitStruct.CounterAlignedMode = ATIM_COUNT_ALIGN_MODE_CENTER_BOTH;    // 
    ATIM_InitStruct.CounterDirection = ATIM_COUNTING_UP;
    ATIM_InitStruct.CounterOPMode = ATIM_OP_MODE_REPETITIVE;    
    ATIM_InitStruct.Prescaler = 4-1; // 计算时钟1MHz
    ATIM_InitStruct.ReloadValue = ARRS;                // 溢出周期100us
    ATIM_InitStruct.RepetitionCounter = 0;
    ATIM_Init(&ATIM_InitStruct);
    
    ATIM_OCInitStruct.BufferState = DISABLE;
    ATIM_OCInitStruct.OCComplement = DISABLE;
    ATIM_OCInitStruct.OCFastMode = DISABLE;    
    ATIM_OCInitStruct.OCInterruptState = ENABLE;
    ATIM_OCInitStruct.OCMode = ATIM_OCMODE_PWM1;    
    ATIM_OCInitStruct.OCPolarity = ATIM_OCPOLARITY_NONINVERT;
    ATIM_OC1Init(&ATIM_OCInitStruct);

    ATIM_OCInitStruct.BufferState = DISABLE;
    ATIM_OCInitStruct.OCComplement = DISABLE;
    ATIM_OCInitStruct.OCFastMode = DISABLE;    
    ATIM_OCInitStruct.OCInterruptState = ENABLE;
    ATIM_OCInitStruct.OCMode = ATIM_OCMODE_PWM1;    
    ATIM_OCInitStruct.OCPolarity = ATIM_OCPOLARITY_NONINVERT;
    ATIM_OC2Init(&ATIM_OCInitStruct);
    
    ATIM_OCInitStruct.BufferState = DISABLE;
    ATIM_OCInitStruct.OCComplement = DISABLE;
    ATIM_OCInitStruct.OCFastMode = DISABLE;    
    ATIM_OCInitStruct.OCInterruptState = ENABLE;
    ATIM_OCInitStruct.OCMode = ATIM_OCMODE_PWM1;    
    ATIM_OCInitStruct.OCPolarity = ATIM_OCPOLARITY_NONINVERT;
    ATIM_OC3Init(&ATIM_OCInitStruct);
		
	ATIM_OCInitStruct.BufferState = DISABLE;
    ATIM_OCInitStruct.OCComplement = DISABLE;
    ATIM_OCInitStruct.OCFastMode = DISABLE;    
    ATIM_OCInitStruct.OCInterruptState = ENABLE;
    ATIM_OCInitStruct.OCMode = ATIM_OCMODE_PWM1;    
    ATIM_OCInitStruct.OCPolarity = ATIM_OCPOLARITY_NONINVERT;
    ATIM_OC4Init(&ATIM_OCInitStruct);
        
    ATIM_SetCompare1(0);
    ATIM_SetCompare2(0);
	ATIM_SetCompare3(0);
	ATIM_SetCompare4(0);
    
	ATIM_CH1Config(ENABLE);
    ATIM_CH2Config(ENABLE); 
	ATIM_CH3Config(ENABLE); 
	ATIM_CH4Config(ENABLE); 

    ATIM_CtrlPWMOutputs(ENABLE);
    ATIM_Cmd(ENABLE);    
}

void set_servo_angle(uint8_t id,int angle){
	int duty = 500 + (angle*1.0/180*2000);
	printf("%d====%d\r\n",id,duty);
	// B3 B4 B5 B6 B0 B1  A3 A0
	switch(id){
		case 0:
			GTIM_SetCompare4(CW_GTIM1, duty);
			break;
		case 1:
			GTIM_SetCompare3(CW_GTIM1, duty);
			break;
		case 2:
			GTIM_SetCompare2(CW_GTIM1, duty);
			break;
		case 3:
			GTIM_SetCompare1(CW_GTIM1, duty);
			break;
		case 4:
			ATIM_SetCompare1(duty);
			break;
		case 5:
			ATIM_SetCompare2(duty);
			break;
		case 6:
			ATIM_SetCompare3(duty);
			break;
		case 7:
			ATIM_SetCompare4(duty);
			break;
	}
}




void set_pin_value(uint8_t pin,uint8_t state){
	
	//// PA1 PA2 PA4 PB2
	switch(pin){
		case 0:
			GPIO_WritePin(CW_GPIOA,GPIO_PIN_1,state);
			break;
		case 1:
			GPIO_WritePin(CW_GPIOA,GPIO_PIN_2,state);
			break;
		case 2:
			GPIO_WritePin(CW_GPIOA,GPIO_PIN_4,state);
			break;
		case 3:
			GPIO_WritePin(CW_GPIOB,GPIO_PIN_2,state);
			break;
	}

}
/************************************************************************/


/*************************** 协议解析 ************************************/
// 帧头(2) | 命令(1) | 数据长度(1) | 数据(n) | 校验位(1) | 帧尾(1)
// AA AA       00       02          00 5A                 BB
#define FRAME_HEAD	0xAA
#define FRAME_FOOT	0xBB
#define FRAME_DATA_MAX_LEN	32		// 数据位最长长度

#define CMD_SET_ANGLE	0x00
#define CMD_SET_PIN		0x01

void do_protocol(uint8_t* buff, uint16_t len);

void Protocol_parse() {
	// 需要最小6字节才能开始解析	
	if(ring_buffer_size(&g_ring) < 6) return;
    
    // 步骤1: 查找帧头 (0xAA 0xAA)
	//取出 0 和 1的位置，去和帧头帧尾进行比较，必须相等
	uint8_t head1;
	uint8_t head2;
	ring_buffer_peek_at(&g_ring, 0, &head1);
	ring_buffer_peek_at(&g_ring, 1, &head2);
	
	if( head1 != FRAME_HEAD || head2 != FRAME_HEAD) {
		// 没有找到了帧头，跳过（丢弃）
		ring_buffer_get(&g_ring, 0);
		
		return;
	} 
    
    // 步骤2: 读取命令位
    uint8_t command;
	ring_buffer_peek_at(&g_ring, 2, &command);
    
    // 步骤3: 读取数据长度
    uint8_t data_len;
	ring_buffer_peek_at(&g_ring, 3, &data_len);
	
	
	if(data_len > FRAME_DATA_MAX_LEN) {
		ring_buffer_get(&g_ring, 0);
		return;
	}
    
    // 检查完整帧是否已到达 (2+1+1+data_len+1+1)
    uint16_t frame_total_len = 6 + data_len;
	
		
    if (ring_buffer_size(&g_ring) < frame_total_len) {
        return;  // 帧不完整，等待更多数据
    }
    
    // 步骤4: 验证帧尾
    uint8_t footer;
	ring_buffer_peek_at(&g_ring, 5 + data_len, &footer);
	
    if (footer != FRAME_FOOT) {
        // 帧尾无效，跳过帧头继续搜索
        ring_buffer_get(&g_ring, 0);
        return;
    }
    
    // 步骤5: 计算校验和 (示例: 简单求和校验)
    uint16_t calc_checksum = 0;
    for (int i = 2; i < 4 + data_len; i++) {
		uint8_t value;
		ring_buffer_peek_at(&g_ring, i, &value);
        calc_checksum += value;
    }
    
    // 获取校验位
    uint8_t checksum;
	ring_buffer_peek_at(&g_ring, 4 + data_len, &checksum);
    
    // 步骤6: 验证校验位 (低8位校验)
    //if ((uint8_t)(calc_checksum & 0xFF) != checksum) {
         // 跳过当前帧头
		//ring_buffer_get(&g_ring, 0);
    //    return;
    //}
	
	// 找到一条协议
	uint8_t tmp[6 + data_len];
    for(uint8_t i = 0; i < 6 + data_len; i++) {
		// 取出数据
		uint8_t value;
		ring_buffer_get(&g_ring, &value);
		tmp[i] = value;
	}
	do_protocol(tmp, 6 + data_len);
}

void do_protocol(uint8_t* buff, uint16_t len) {
	uint8_t cmd = buff[2];
	printf("cmd=%d\r\n",cmd);
	if(cmd == CMD_SET_ANGLE) {
		// AA AA 00 02 00 5A  BB
		// 命令(1) | 数据长度(1) | 数据(n) 
		// 	??	  | 2		  |  id(1)	angle(1)
		uint8_t id = buff[4];
		uint8_t angle = buff[5];
		set_servo_angle(id,angle);
	} else if(cmd == CMD_SET_PIN) {
		uint8_t pin = buff[4];
		uint8_t value = buff[5];
		
		set_pin_value(pin,value);
	}
}

/**********************************************************************/

/**
 * @brief Retargets the C library printf function to the UART.
 *
 */
/*
PUTCHAR_PROTOTYPE
{
    UART_SendData_8bit(DEBUG_UARTx, (uint8_t)ch);

    while (UART_GetFlagStatus(DEBUG_UARTx, UART_FLAG_TXE) == RESET);

    return ch;
}

size_t __write(int handle, const unsigned char * buffer, size_t size)
{
    size_t nChars = 0;

    if (buffer == 0)
    {
        
    //    return 0;
    //}


    for (; size != 0; --size)
    {
        UART_SendData_8bit(DEBUG_UARTx, *buffer++);
        while (UART_GetFlagStatus(DEBUG_UARTx, UART_FLAG_TXE) == RESET);
        ++nChars;
    }

    return nChars;
		
		
}*/

/******************************************************************************
 * EOF (not truncated)
 ******************************************************************************/
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
    /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
       tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */


   
#if defined (__GNUC__) && !defined (__clang__)
    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
    #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif

// 发送单个字符
void UART_SendChar(char ch)
{
    while ((DEBUG_UARTx->ISR & UARTx_ISR_TXBUSY_Msk) == UARTx_ISR_TXBUSY_Msk); // 等待发送完成
    DEBUG_UARTx->TDR = ch; // 发送字符
}
/*******************************************************************************
 * @brief  重定向C库中Printf函数到UART.
 * @retval None
 * @note   None
 */
__WEAK PUTCHAR_PROTOTYPE
{
    UART_SendChar((char)ch);
    return ch;
}
